﻿namespace Microsoft.VisualStudio.ServiceModel.DomainServices.Tools
{
    using Microsoft.ServiceModel.DomainServices.Tools;
    using System;
    using System.CodeDom;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    internal sealed class DomainServiceFixupCodeDomVisitor : CodeDomVisitor
    {
        private CodeGenContext _context;

        public DomainServiceFixupCodeDomVisitor(CodeGenContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            this._context = context;
        }

        private void FixUpNamespaceRootNamespace(CodeNamespace ns)
        {
            string rootNamespace = this.RootNamespace;
            if (!this.IsCSharp && !string.IsNullOrEmpty(rootNamespace))
            {
                string name = ns.Name;
                if (name.Equals(rootNamespace, StringComparison.Ordinal))
                {
                    ns.Name = string.Empty;
                }
                else if (name.StartsWith(rootNamespace + ".", StringComparison.Ordinal))
                {
                    ns.Name = name.Substring(rootNamespace.Length + 1);
                }
            }
        }

        private static string GetAttributeId(CodeAttributeDeclaration attribute)
        {
            StringBuilder builder = new StringBuilder(attribute.Name);
            foreach (CodeAttributeArgument argument in attribute.Arguments)
            {
                CodePrimitiveExpression expression = argument.Value as CodePrimitiveExpression;
                builder.Append(argument.Name);
                if ((expression != null) && (expression.Value != null))
                {
                    builder.Append(expression.Value.ToString());
                }
                else
                {
                    builder.Append(argument.Value.ToString());
                }
            }
            return builder.ToString();
        }

        protected override void VisitCodeAttributeDeclarationCollection(CodeAttributeDeclarationCollection codeAttributeDeclarationCollection)
        {
            CodeAttributeDeclaration[] declarationArray = (from a in codeAttributeDeclarationCollection.Cast<CodeAttributeDeclaration>()
                orderby GetAttributeId(a)
                select a).ToArray<CodeAttributeDeclaration>();
            codeAttributeDeclarationCollection.Clear();
            codeAttributeDeclarationCollection.AddRange(declarationArray);
            base.VisitCodeAttributeDeclarationCollection(codeAttributeDeclarationCollection);
        }

        protected override void VisitCodeNamespaceCollection(CodeNamespaceCollection codeNamespaceCollection)
        {
            CodeNamespace[] namespaceArray = (from ns in codeNamespaceCollection.Cast<CodeNamespace>()
                orderby ns.Name
                select ns).ToArray<CodeNamespace>();
            codeNamespaceCollection.Clear();
            if (this.IsCSharp)
            {
                codeNamespaceCollection.AddRange(namespaceArray);
            }
            else
            {
                foreach (CodeNamespace namespace2 in namespaceArray)
                {
                    this.FixUpNamespaceRootNamespace(namespace2);
                    codeNamespaceCollection.Add(namespace2);
                }
            }
            base.VisitCodeNamespaceCollection(codeNamespaceCollection);
        }

        protected override void VisitCodeNamespaceImportCollection(CodeNamespaceImportCollection codeNamespaceImportCollection)
        {
            CodeNamespaceImport[] importArray = codeNamespaceImportCollection.Cast<CodeNamespaceImport>().OrderBy<CodeNamespaceImport, string>(i => i.Namespace, new NamespaceImportComparer()).Distinct<CodeNamespaceImport>().ToArray<CodeNamespaceImport>();
            codeNamespaceImportCollection.Clear();
            codeNamespaceImportCollection.AddRange(importArray);
            base.VisitCodeNamespaceImportCollection(codeNamespaceImportCollection);
        }

        protected override void VisitCodeTypeDeclarationCollection(CodeTypeDeclarationCollection codeTypeDeclarationCollection)
        {
            CodeTypeDeclaration[] declarationArray = (from c in codeTypeDeclarationCollection.Cast<CodeTypeDeclaration>()
                orderby c.Name
                select c).ToArray<CodeTypeDeclaration>();
            codeTypeDeclarationCollection.Clear();
            codeTypeDeclarationCollection.AddRange(declarationArray);
            base.VisitCodeTypeDeclarationCollection(codeTypeDeclarationCollection);
        }

        private bool IsCSharp
        {
            get
            {
                return this._context.IsCSharp;
            }
        }

        private string RootNamespace
        {
            get
            {
                return this._context.RootNamespace;
            }
        }

        private class NamespaceImportComparer : IComparer<string>
        {
            public int Compare(string x, string y)
            {
                bool flag = x.Equals("System", StringComparison.Ordinal) || x.StartsWith("System.", StringComparison.Ordinal);
                bool flag2 = y.Equals("System", StringComparison.Ordinal) || y.StartsWith("System.", StringComparison.Ordinal);
                if (flag && !flag2)
                {
                    return -1;
                }
                if (!flag && flag2)
                {
                    return 1;
                }
                return string.Compare(x, y, StringComparison.Ordinal);
            }
        }
    }
}

